package logique.calculateur;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;

import logique.administration.Modification;
import logique.reseau.Troncon;
import logique.reseau.Ville;

public class Itineraire {
	private int score;
	private int duree;
	private int distance;
	private Ville depart;
	private Ville objectifCourant;
	private Troncon tronconCourant;
	private ListIterator<Troncon> curseur;
	private LinkedList<Troncon> troncons;
	
	
	public Itineraire(Ville depart, LinkedList<Troncon> troncons) {
		this.depart = depart;
		this.troncons = troncons;
		score = 0;
		duree = 0;
		distance = 0;
		
		for (Troncon t : troncons){
			score += t.getEvaluations().getScore();
			duree += t.getDuree();
			distance += t.getLongueur();
		}
		curseur = troncons.listIterator();
		objectifCourant = depart;
	}
	
	public Itineraire(Ville depart, int score, LinkedList<Troncon> troncons) {
		this.depart = depart;
		this.score = score;
		this.troncons = troncons;
		for (Troncon t : troncons){
			duree += t.getDuree();
			distance += t.getLongueur();
		}
		curseur = troncons.listIterator();
		objectifCourant = depart;	
	}
	
	public Itineraire(Ville depart, ArrayList<Itineraire> liste) {
		this.depart = depart;
		score = 0;
		duree = 0;
		distance = 0;
		
		troncons = new LinkedList<Troncon>();
		
		for (Itineraire it : liste){
			troncons.addAll(it.getTroncons());
			score += it.getScore();
			duree += it.getDuree();
			distance += it.getDistance();
		}
		curseur = troncons.listIterator();
		objectifCourant = depart;
	}
	
	public Itineraire(Itineraire it){
		this.depart = it.depart;
		score = it.getScore();
		duree = it.getDuree();
		distance = it.getDistance();
		troncons = new LinkedList<Troncon>(it.getTroncons());
		curseur = troncons.listIterator();
		objectifCourant = depart;
	}

	public int getDuree(){
		return duree;
	}
	
	public int getDistance(){
		return distance;
	}
	/**
	 * Retourne le nombre de tronçon de l'itineraire
	 * @return
	 */
	public int getLongueur(){
		return troncons.size();
	}
	
	/**
	 * Tente de passer à l'étape suivante et retourne vrai si réussi.
	 * @return
	 */
	public boolean etapeSuivante(){
		if( curseur.hasNext() ){
			tronconCourant = curseur.next();
			objectifCourant = tronconCourant.getExtremite(objectifCourant);
			return true;
		}
		return false;
	}
	
	/**
	 * Tente de passer à l'étape précédente et retourne vrai si réussi.
	 * @return
	 */
	public boolean etapePrecedente(){
		if( curseur.hasPrevious() ){
			tronconCourant = curseur.previous();
			objectifCourant = tronconCourant.getExtremite(objectifCourant);
			return true;
		}
		return false;
	}

	public int getScore() {
		return score;
	}

	public Ville getObjectifCourant() {
		return objectifCourant;
	}

	public Troncon getTronconCourant() {
		return tronconCourant;
	}

	public LinkedList<Troncon> getTroncons() {
		return troncons;
	}

	public ListIterator<Troncon> getCurseur() {
		return curseur;
	}
	
	public String toString(){
		StringBuffer buf = new StringBuffer();
		for (Troncon t : troncons) {
			buf.append(t + "\n");
		}
		return buf.toString();
	}
	
	/**
	 * Retourne l'itineraire inverse
	 * @return
	 */
	public Itineraire inverse(){
		LinkedList<Troncon> listeInv = new LinkedList<Troncon>();
		Ville oldObj = objectifCourant;
		ListIterator<Troncon> oldCur = curseur;
		Troncon oldTroncon = tronconCourant;
		objectifCourant = depart;
		curseur = troncons.listIterator();
		while( etapeSuivante() ){
			listeInv.addFirst(tronconCourant);
		}
		Ville arrivee = objectifCourant;
		objectifCourant = oldObj;
		curseur = oldCur;
		tronconCourant = oldTroncon;
		return new Itineraire(arrivee, score, listeInv);
	}
	
	public void setCurseur(int index){
		curseur = troncons.listIterator(index);
	}
	
	public void setObjectifCourant(Ville v){
		objectifCourant = v;
	}
	
	public synchronized boolean estAffectePar(Modification m){
		ListIterator<Troncon> it = curseur;
		boolean affect = false;
		while (it.hasNext()) {
			if( m.affecte(it.next()) ){
				affect = true;
				break;
			}
		}
		return affect;
	}
}
